import type { GenMessage } from "@bufbuild/protobuf/codegenv1";
import { EzGameNetManager } from "./EzGameNetManager";

export class EzGameReqInstance<R,S>{
    public static readonly STATUS_NOSEND = 0;
    public static readonly STATUS_SENDING = 1;
    public static readonly STATUS_WAITRETURN = 2;
    public static readonly STATUS_RETURNED = 3;
    public static readonly STATUS_SENDFAIL = 4;
    public static readonly STATUS_RETURNTIMEOUT = 5;
    public static readonly STATUS_SENDDONE = 6;
    //发送给服务器的真实数据
    public reqData:R|null = null;
    public reqDataEncoder?:(data:R)=>Uint8Array

    //服务器返回的真实数据
    public respData:S| null = null;
    public respCode:number = 0
    public respErrorMsg:string = ""
    public respDataDecoder?:(data:Uint8Array)=>S|null



    //客户端定义的消息序列号
    public msgSerial:number = 0;
    //服务器定义的业务id
    public cmd:number = 0;



    //成功返回的回调
    public respHandler?:(resp:EzGameReqInstance<R,S>)=>void;



    public resolve?:Function
    public reject?:(req:EzGameReqInstance<any,any>)=>void

    private isAsync:boolean = false;

    public get async():boolean{
        return this.isAsync;
    }
    /**
     * 0:未发送,1正在发送， 2:等待返回 3:已返回 4:发送失败 5:返回超时 6：发送完成
     * 有返回值得状态变化：
     *  0未发送 ->1正在发送-> 4发送失败
     *  0未发送 ->1正在发送-> 2等待返回 ->3已返回 
     *  0未发送 ->1正在发送-> 2等待返回 ->5返回超时
     * 
     * 无返回值得状态变化：
     *   0未发送 ->1正在发送-> 4发送失败
     *   0未发送 ->1正在发送-> 6发送完成
     */

    // 0:未发送,1正在发送， 2:等待返回 3:已返回 4:发送失败 5:返回超时 6：发送完成
    public status:number = EzGameReqInstance.STATUS_NOSEND; 

    public netName:string = "default"; // 默认网络名称

    public sendTime:number = 0;
    public respTime:number = 0;

    public timeOutId:number = 0; //超时定时器id

    net(netName: string) {
        if(netName) {
            this.netName = netName;
            return this
        }
        throw new Error("网络名称不能为空，请使用net('网络名称')方法设置网络名称");
    }

    public onResp(cb:(resp:EzGameReqInstance<R,S>)=>void){
        this.respHandler = cb;
        return this;
    }

    public static create<Req,Resp>(req:Req){
        let ins = new EzGameReqInstance<Req,Resp>();
        ins.reqData = req;
        return ins
    }
    public static createWithNoParam<Req,Resp>(){
        let ins = new EzGameReqInstance<Req,Resp>();
        return ins
    }

    public reqParam(cb:(req:R)=>R){ 
        this.reqData = cb(this.reqData as R);
        return this;
    }

    //发送请求，同步
    public send():Promise<S>{
        //TODO 下面得这些错误也算是请求错误，需要执行错误回调？
        if(this.status!= EzGameReqInstance.STATUS_NOSEND) {
            throw new Error("当前请求已经发送过了，不能重复发送");
        }
        if(this.isAsync){
            throw new Error("当前请求是异步的，不能使用同步发送");
        }

        // CommandManager.writeAndFlush(this);
        let net = EzGameNetManager.get(this.netName)
        if(net == null) {
            throw new Error(`网络连接 ${this.netName} 不存在，请先注册网络连接`);
        }
        this.status = EzGameReqInstance.STATUS_SENDING;
        this.isAsync = false;
        //消息转换为byte数组
        return new Promise((r,j)=>{
            this.resolve = r;
            this.reject = j;
            net.sendMsg(this);
        })

    }
    public sendAsync(){
        //TODO 下面得这些错误也算是请求错误，需要执行错误回调？
        if(this.status!= EzGameReqInstance.STATUS_NOSEND) {
            throw new Error("当前请求已经发送过了，不能重复发送");
        }
        if(this.isAsync){
            throw new Error("当前请求是异步的，不能使用同步发送");
        }

        let net = EzGameNetManager.get(this.netName)
        if(net == null) {
            throw new Error(`网络连接 ${this.netName} 不存在，请先注册网络连接`);
        }
        this.status = EzGameReqInstance.STATUS_SENDING;
        this.isAsync = true
        this.resolve = this.respHandler
        net.sendMsg(this);
    }
}

